﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace PowerMonitor.Common
{
    class MemData
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr CreateFileMapping(int hFile, IntPtr lpAttributes, ePageAccess flProtect, uint dwMaxSizeHi, uint dwMaxSizeLow, string lpName);
        
        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr OpenFileMapping(eFileAccess fileAccess,[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,string lpName);

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr MapViewOfFile(IntPtr hFileMapping,eFileAccess dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow,uint dwNumberOfBytesToMap);

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool UnmapViewOfFile(IntPtr pvBaseAddress);

        [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);

        [DllImport("kernel32", EntryPoint="GetLastError")]
        public static extern int GetLastError ();

        const int ERROR_ALREADY_EXISTS = 183;
        public enum eFileAccess
        {
            FILE_MAP_COPY = 0x0001,
            FILE_MAP_WRITE = 0x0002,
            FILE_MAP_READ = 0x0004,
            FILE_MAP_ALL_ACCESS = 0x0002 | 0x0004,
        }

        public enum ePageAccess
        {
            PAGE_READONLY = 0x02,
            PAGE_READWRITE = 0x04,
            PAGE_WRITECOPY = 0x08,
            PAGE_EXECUTE = 0x10,
            PAGE_EXECUTE_READ = 0x20,
            PAGE_EXECUTE_READWRITE = 0x40,
        }

        public enum eSEC_Flag 
        {
            SEC_COMMIT = 0x8000000,
            SEC_IMAGE = 0x1000000,
            SEC_NOCACHE = 0x10000000,
            SEC_RESERVE = 0x4000000,
        }


        const int INVALID_HANDLE_VALUE = -1;

        string m_strName = DateTime.Now.ToString("YYYY-mm-DD HH:MM:SS");
        IntPtr m_hSharedMemoryFile = IntPtr.Zero;
        IntPtr m_pwData = IntPtr.Zero;
        bool m_bInit = false;
        long m_MemSize=0;

        public MemData(string strName,long lngSize)
        {
            m_strName = strName;
            m_bInit = CreateFileMapping(lngSize);
        }
        ~MemData()
        {
            Close();
        }

        /**//// <summary>
        /// 初始化共享内存
        /// </summary>
        /// <param name="strName">共享内存名称</param>
        /// <param name="lngSize">共享内存大小</param>
        /// <returns></returns>
        public bool CreateFileMapping(long lngSize)
        {
            if (lngSize <= 0 || lngSize > 0x00800000) lngSize = 0x00800000;
            m_MemSize = lngSize;

            if (m_strName.Length > 0)
            {
                m_hSharedMemoryFile = OpenFileMapping(eFileAccess.FILE_MAP_ALL_ACCESS, false, m_strName);
                if (m_hSharedMemoryFile == IntPtr.Zero)
                {
                    m_hSharedMemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, IntPtr.Zero, ePageAccess.PAGE_READWRITE, 0, (uint)lngSize, m_strName);
                    if (m_hSharedMemoryFile == IntPtr.Zero)
                    {
                        m_bInit = false;
                        Exception ex = new Exception("创建共享内存失败,程序无法正常运行！");
                        throw ex;
                    }
                }

                //else
                //{
                //    if (GetLastError() == ERROR_ALREADY_EXISTS)  //已经创建
                //    {
                //        m_bAlreadyExist = true;
                //    }
                //    else                                         //新创建
                //    {
                //        m_bAlreadyExist = false;
                //    }
                //}
            }
            else
            {
                return false; //参数错误     
            }
            return true;     //创建成功
        }

        public IntPtr OpenMapping(eFileAccess fileAccess, uint lngAddr,uint lngSize)
        {
            // ---------------------------------------
            // 创建内存映射
            if (m_hSharedMemoryFile == IntPtr.Zero)
            {
                return IntPtr.Zero; //创建共享体失败
            }
            IntPtr ResIntPrt = IntPtr.Zero;
            ResIntPrt = MapViewOfFile(m_hSharedMemoryFile, fileAccess, 0, lngAddr, (uint)lngSize);
            int iErr = GetLastError();          
            if (ResIntPrt == IntPtr.Zero)
            {
                CloseHandle(m_hSharedMemoryFile);
                Exception ex = new Exception("打开内存共享文件失败！" + iErr.ToString("X4"));
                throw ex;
            }
            
            return ResIntPrt;
        }
        /**//// <summary>
        /// 关闭共享内存
        /// </summary>
        public void Close()
        {
            if (m_bInit)
            {
                UnmapViewOfFile(m_pwData);
                CloseHandle(m_hSharedMemoryFile);
            }
        }

        /// <summary>
        /// 读数据
        /// </summary>
        /// <param name="bytData">数据</param>
        /// <param name="lngAddr">起始地址</param>
        /// <param name="lngSize">个数</param>
        /// <returns></returns>
        public bool Read(ref byte[] bytData, int lngAddr, int lngSize)
        {
            if (lngAddr + lngSize > m_MemSize) return false; //超出数据区
            if (m_bInit)
            {
                Marshal.Copy(m_pwData, bytData, lngAddr, lngSize);
            }
            else
            {
                return false; //共享内存未初始化
            }
            return true;     //读成功
        } 
        /// <summary>
        /// 写数据
        /// </summary>
        /// <param name="bytData">数据</param>
        /// <param name="lngAddr">起始地址</param>
        /// <param name="lngSize">个数</param>
        /// <returns></returns>
        public bool Write(byte[] bytData, int lngAddr, int lngSize)
        {
            if (lngAddr + lngSize > m_MemSize) return false; //超出数据区
            if (m_bInit)
            {
                Marshal.Copy(bytData, lngAddr, m_pwData, lngSize);
            }
            else
            {
                return false; //共享内存未初始化
            }
            return true;     //写成功
        }
        /// <summary>
        /// 写结构体对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Item"></param>
        /// <param name="Addr"></param>
        /// <returns></returns>
        public bool WriteObject<T>( int Addr,T Item) where T:struct
        {          
            if (m_bInit)
            {
                uint lSize = (uint)Marshal.SizeOf(typeof(T));
                IntPtr tempIntPrt = OpenMapping(eFileAccess.FILE_MAP_WRITE, (uint)Addr, lSize);
                Marshal.StructureToPtr(Item, tempIntPrt, true);
                UnmapViewOfFile(tempIntPrt);
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 读取结构体对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Addr"></param>
        /// <returns></returns>
        public T ReadObject<T>(int Addr) where T : struct
        {
            if (m_bInit)
            {
                uint lSize = (uint)Marshal.SizeOf(typeof(T));
                IntPtr tempIntPrt = OpenMapping(eFileAccess.FILE_MAP_READ, (uint)Addr, lSize);
                if (IntPtr.Zero == tempIntPrt)
                {
                    return (T)Marshal.PtrToStructure(tempIntPrt, typeof(T));
                }
                else
                {
                    Exception ex = new Exception("共享内存数据读取失败！");
                    throw ex;
                }
            }
            else
            {
                Exception ex = new Exception("共享内存数据读取失败！");
                throw ex;
            }
        }
    }
}
